package com.gmlive.common.ui.widget;

import android.content.Context;
import android.database.DataSetObserver;
import android.os.Parcelable;

import androidx.annotation.NonNull;
import androidx.core.view.ViewCompat;
import androidx.viewpager.widget.PagerAdapter;
import androidx.viewpager.widget.ViewPager;

import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;

@SuppressWarnings("unused, ClickableViewAccessibility")
public class IkUIViewPager extends ViewPager {
    private static final int DEFAULT_INFINITE_RATIO = 100;

    private boolean mIsSwipeable = true;
    private boolean mIsInMeasure = false;
    private boolean mEnableLoop = false;
    private int mInfiniteRatio = DEFAULT_INFINITE_RATIO;

    public static final int DIRECTION_LEFT = 1;
    public static final int DIRECTION_RIGHT = 1 << 1;

    private static final int DIRECTION_BOTH = DIRECTION_LEFT | DIRECTION_RIGHT;

    private int mDirection = DIRECTION_BOTH;

    private float initialXValue;

    public IkUIViewPager(Context context) {
        this(context, null);
    }

    public IkUIViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public void setSwipeable(boolean enable) {
        mIsSwipeable = enable;
    }

    public int getInfiniteRatio() {
        return mInfiniteRatio;
    }

    public void setInfiniteRatio(int infiniteRatio) {
        mInfiniteRatio = infiniteRatio;
    }

    public boolean isEnableLoop() {
        return mEnableLoop;
    }

    public void setEnableLoop(boolean enableLoop) {
        if (mEnableLoop != enableLoop) {
            mEnableLoop = enableLoop;
            if (getAdapter() != null) {
                getAdapter().notifyDataSetChanged();
            }
        }
    }

    /**
     * 控制滑动方向
     */
    public void setScrollDirection(int direction) {
        mDirection = direction;
    }

    private boolean canScrollLeft() {
        return (mDirection & DIRECTION_LEFT) == DIRECTION_LEFT;
    }

    private boolean canScrollRight() {
        return (mDirection & DIRECTION_RIGHT) == DIRECTION_RIGHT;
    }

    @Override
    public void addView(View child, int index, ViewGroup.LayoutParams params) {
        super.addView(child, index, params);
        ViewCompat.requestApplyInsets(this);
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        if (isSwipeAllowed(ev)) {
            return mIsSwipeable && super.onTouchEvent(ev);
        } else {
            return false;
        }
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        if (isSwipeAllowed(ev)) {
            return mIsSwipeable && super.onInterceptTouchEvent(ev);
        } else {
            return false;
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        mIsInMeasure = true;
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        mIsInMeasure = false;
    }

    public boolean isInMeasure() {
        return mIsInMeasure;
    }

    @Override
    public void setAdapter(PagerAdapter adapter) {
        if (adapter instanceof IkUIPagerAdapter) {
            super.setAdapter(new WrapperPagerAdapter((IkUIPagerAdapter) adapter));
        } else {
            super.setAdapter(adapter);
        }
    }

    private boolean isSwipeAllowed(MotionEvent event) {
        if (this.mDirection == DIRECTION_BOTH) return true;

        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            initialXValue = event.getX();
            return true;
        }

        if (event.getAction() == MotionEvent.ACTION_MOVE) {
            try {
                float diffX = event.getX() - initialXValue;
                if (diffX > 0 && !canScrollRight()) {
                    // swipe from left to right detected
                    return false;
                } else if (diffX < 0 && !canScrollLeft()) {
                    // swipe from right to left detected
                    return false;
                }
            } catch (Exception exception) {
                exception.printStackTrace();
            }
        }

        return true;
    }

    class WrapperPagerAdapter extends PagerAdapter {
        private IkUIPagerAdapter mAdapter;

        WrapperPagerAdapter(IkUIPagerAdapter adapter) {
            mAdapter = adapter;
        }

        @Override
        public int getCount() {
            int count = mAdapter.getCount();
            if (mEnableLoop && count >= 2) {
                count *= mInfiniteRatio;
            }
            return count;
        }

        @NonNull
        @Override
        public Object instantiateItem(@NonNull ViewGroup container, int position) {
            int realPosition = position;
            if (mEnableLoop && mAdapter.getCount() != 0) {
                realPosition = position % mAdapter.getCount();
            }
            return mAdapter.instantiateItem(container, realPosition);
        }

        @Override
        public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
            int realPosition = position;
            if (mEnableLoop && mAdapter.getCount() != 0) {
                realPosition = position % mAdapter.getCount();
            }
            mAdapter.destroyItem(container, realPosition, object);
        }

        @Override
        public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
            return mAdapter.isViewFromObject(view, object);
        }

        @Override
        public void restoreState(Parcelable bundle, ClassLoader classLoader) {
            mAdapter.restoreState(bundle, classLoader);
        }

        @Override
        public Parcelable saveState() {
            return mAdapter.saveState();
        }

        @Override
        public void startUpdate(@NonNull ViewGroup container) {
            mAdapter.startUpdate(container);
        }

        @Override
        public void finishUpdate(@NonNull ViewGroup container) {
            mAdapter.finishUpdate(container);
        }

        @Override
        public CharSequence getPageTitle(int position) {
            int virtualPosition = position % mAdapter.getCount();
            return mAdapter.getPageTitle(virtualPosition);
        }

        @Override
        public float getPageWidth(int position) {
            return mAdapter.getPageWidth(position);
        }

        @Override
        public void setPrimaryItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
            mAdapter.setPrimaryItem(container, position, object);
        }

        @Override
        public void unregisterDataSetObserver(@NonNull DataSetObserver observer) {
            mAdapter.unregisterDataSetObserver(observer);
        }

        @Override
        public void registerDataSetObserver(@NonNull DataSetObserver observer) {
            mAdapter.registerDataSetObserver(observer);
        }

        @Override
        public void notifyDataSetChanged() {
            super.notifyDataSetChanged();
            mAdapter.notifyDataSetChanged();
        }

        @Override
        public int getItemPosition(@NonNull Object object) {
            return mAdapter.getItemPosition(object);
        }
    }
}
